#!/usr/bin/env python
#
'''
Created on 2009-3-25

@author: Wang_Yuan
'''

import array
import datetime
import random
import os.path

import wx
import wx.wizard as wiz

import core

from ExamSettingPanel import *
from ExamSettingConfirmPanel import *
from QuestionPanels import *

class ExamSettings:
    '''
    Exam Settings
    '''
    
    Q_TYPE_MEANINGS2WORD = 1
    Q_TYPE_EXAMPLE2WORD = 1 << 1
    Q_TYPE_WORD2MEANINGS = 1 << 2
    Q_TYPE_ALL = Q_TYPE_MEANINGS2WORD | Q_TYPE_EXAMPLE2WORD | Q_TYPE_WORD2MEANINGS
    
    def __init__(self):
        self.qType = 0
        self.qAmount = 0
        
    def addQType(self, type):
        self.qType |= type
    
    def getQTypes(self):
        if not self.qType:
            self.qType = ExamSettings.Q_TYPE_ALL
        return self.qType
    
    def getQTypeIndexes(self):
        l = []
        t = self.getQTypes()
        i = 0
        while t:
            if t & 1:
                l.append(i)
            i += 1
            t >>= 1
        return l if l else xrange(3)
    
    def getQAmount(self):
        return self.qAmount
    

class ExamQuestion:
    '''
    Exam question class, include answer. 
    '''
    
    def __init__(self, vocabulary, wordData, typeIndexes):
        self.vocabulary = vocabulary
        self.wordData = wordData
        allTypes = range(3)
        typeIndexes = list(typeIndexes)
        if not wordData.hasExamples():
            if 1 in typeIndexes:
                typeIndexes.remove(1)
            allTypes.remove(1)
        if not wordData.hasNonEnglishMeanings():
            if 2 in typeIndexes:
                typeIndexes.remove(2)
            allTypes.remove(2)
        if not (wordData.hasNonEnglishMeanings() or wordData.hasEnglishMeanings()):
            if 0 in typeIndexes:
                typeIndexes.remove(0)
            if 2 in typeIndexes:
                typeIndexes.remove(2)
            allTypes.remove(0)
            if 2 in allTypes:
                allTypes.remove(2)
                
        if typeIndexes:
            self.typeIndex = random.choice(typeIndexes)
        else:
            self.typeIndex = random.choice(allTypes)
        setupFuncs = [
                      self.setupMeaning2word, 
                      self.setupExample2word, 
                      self.setupWord2Meanings, 
                      ]
        self.validated = False
        for i in xrange(len(setupFuncs)):
            index = (self.typeIndex + i) % len(setupFuncs)
            if index in typeIndexes:
                setupFuncs[index]()
                if self.validated:
                    self.typeIndex = index
                    break
        self.lastRecord = self.wordData.records[0] if self.wordData.records else None
        self.oxRecords = []
        
    def setupMeaning2word(self):
        nonEnMeaningList = self.wordData.getNonEnglishAtomMeaningList()
        enMeaningList = self.wordData.getEnglishAtomMeaningList()
        random.shuffle(nonEnMeaningList)
        random.shuffle(enMeaningList)
        self.meaningList = nonEnMeaningList + enMeaningList
        self.answer = self.wordData.word
        self.validated = (self.meaningList and self.answer)
    
    def setupExample2word(self):
        self.example = self.wordData.getRandomExample()
        self.answer = self.example.answer
        self.validated = (self.example and self.answer)
    
    def setupWord2Meanings(self):
        self.word = self.wordData.word
        self.pronunciation = self.wordData.pronunciation
        self.meaningList = self.wordData.getNonEnglishAtomMeaningList()
        self.validated = (self.word and self.meaningList)
        
    def recordScore(self, score):
        record = core.ExaminRecord()
        record.score = score
        if not self.lastRecord or self.lastRecord.score != record.score or (record.getDate() - self.lastRecord.getDate()) > datetime.timedelta(milliseconds=500):
            self.wordData.addRecord(record)
            self.lastRecord = self.wordData.records[0]
            
    def addOXRecord(self, right=True):
        self.oxRecords.append(right)
    
class PanelWizardPage(wiz.PyWizardPage):
    '''
    Wizard page for exam. 
    '''
    
    def __init__(self, parent, getPanel):
        wiz.PyWizardPage.__init__(self, parent)
        sizer = wx.BoxSizer(wx.VERTICAL)
        self.panel = getPanel(self)
        sizer.Add(self.panel, proportion=1, flag=wx.EXPAND)
        self.SetSizer(sizer)
        sizer.Fit(self)
        

class ExamSettingsWizardPage(PanelWizardPage):
    '''
    Wizard page for exam settings
    '''
    
    def __init__(self, parent, vocabulary):
        PanelWizardPage.__init__(self, parent, getExamSettingPanelBuilder(vocabulary))
        self.confirmPage = ExamSettingsConfirmWizardPage(parent, getExamSettingConfirmPanelBuilder(), self)
        
    def GetPrev(self):
        return None
    
    def GetNext(self):
        print 'setting page get next'
        settings = self.panel.getSettings()
        self.confirmPage.panel.setSettings(settings)
        return self.confirmPage
    
class ExamSettingsConfirmWizardPage(PanelWizardPage):
    '''
    Wizard page for exam setting confirm
    '''
    
    def __init__(self, parent, getPanel, settingsPage):
        PanelWizardPage.__init__(self, parent, getPanel)
        self.settingsPage = settingsPage
        self.settingsPanel = settingsPage.panel
        
    def GetPrev(self):
        return self.settingsPage
    
    def GetNext(self):
        return None
#        print 'confirm page get next'
#        settings = self.settingsPanel.getSettings()
#        qTypeIndexes = settings.getQTypeIndexes()
#        questionList = map(lambda data: ExamQuestion(data, qTypeIndexes), 
#                           self.settingsPanel.examWordList)
#        flag = False
#        for index, question in zip(xrange(len(questionList)), questionList):
#            if question.validated:
#                flag = True
#                break
#        if flag:
#            questionPage = QuestionWizardPage(self.GetParent(), index, questionList)
#            return questionPage
#        else:
#            return None


class QuestionWizardPage(PanelWizardPage):
    '''
    Wizard page for questions. 
    '''
    
    def __init__(self, parent, index, questionList):
        PanelWizardPage.__init__(self, parent, getQuestionPanelBuilder(index, questionList))
        self.index = index
        self.questionList = questionList
        self.answerPage = self
        
    def GetPrev(self):
        return None
    
    def GetNext(self):
        print 'question page %s get next' % (self.index)
        if self.answerPage == self and self.panel.isAnswered():
            self.answerPage = AnswerWizardPage(self.GetParent(), self.index, self.questionList, self.panel)
        return self.answerPage
    
    def GetBitmap(self):
        return getQuestionBitmap()
    
class AnswerWizardPage(PanelWizardPage):
    '''
    Wizard page for answers. 
    '''
    
    def __init__(self, parent, index, questionList, prev):
        PanelWizardPage.__init__(self, parent, getAnswerPanelBuilder(index, questionList, prev))
        self.nextIndex = index + 1
        self.questionList = questionList
        self.nextQuestionPage = self
        
    def GetPref(self):
        return None
    
    def GetNext(self):
        print 'answer page %s get next' % (self.nextIndex)
        if self.nextIndex < len(self.questionList):
            flag = False
            for index, question in zip(xrange(self.nextIndex, len(self.questionList)), self.questionList[self.nextIndex:]):
                if question.validated:
                    flag = True
                    break
            if flag:
                if self.nextQuestionPage == self:
                    self.nextQuestionPage = QuestionWizardPage(self.GetParent(), index, self.questionList)
                return self.nextQuestionPage
            else:
                return None
        else:
            return None
        
    def GetBitmap(self):
        print 'get bitmap'
        return getAnswerBitmap()
    
sideImages = {}

imageBgs = {
            'settings': lambda r: array.array('B', [r, r, r>>1]), 
            'questions': lambda r: array.array('B', [r, r>>2, r>>4]), 
            'answers': lambda r: array.array('B', [0, 0, r])
            }

def getSideBitmap(key):
    image = sideImages.get(key)
    if not image:
        path = os.path.realpath('ui/img/%s.png' % (key,))
        if os.path.exists(path):
            image = wx.Bitmap(path)
            bpp = 3
            data = array.array('B', [0] * image.GetWidth() * image.GetHeight() * bpp)
            try:
                image.CopyToBuffer(data, wx.BitmapBufferFormat_RGB)
                if data[0:3] == array.array('B', [0xff, 0, 0]):
                    alphaData = array.array('B', [0xff] * image.GetWidth() * image.GetHeight())
                    for y in xrange(image.GetHeight()):
                        for x in xrange(image.GetWidth()):
                            offset = y * image.GetWidth() * bpp + x * bpp
                            alphaOffset = y * image.GetWidth() + x
                            r,g,b = data[offset:offset+3]
                            if r > g or r > b:
                                data[offset:offset+3] = imageBgs[key](r)
                                power = 3
                                alphaData[alphaOffset] = 0xff - r * y ** power / (image.GetHeight() - 1) ** power
                    image = wx.BitmapFromBuffer(image.GetWidth(), image.GetHeight(), data, alphaData)
            except:
                pass
            sideImages[key] = image
        else:
            image = wx.NullBitmap
    return image

def getQuestionBitmap():
    return getSideBitmap('questions')

def getSettingBitmap():
    return getSideBitmap('settings')

def getAnswerBitmap():
    return getSideBitmap('answers')
